<?php defined('SYSPATH') or die('No direct script access.');
/**
 * 重载并扩展 Kohana_Database_Query_Builder_Select 类
 *
 * @author  Yellow.Chow <aultoale@gmail.com>
 * @version $Id: select.php 43 2012-03-09 08:24:10Z yellow.chow $
 * @license http://www.gnu.org/licenses/gpl-3.0.html    GPL 3
 */

/**
 * Database query builder for SELECT statements. See [Query Builder](/database/query/builder) for usage and examples.
 *
 * @package    Kohana/Database
 * @category   Query
 * @author     Kohana Team
 * @copyright  (c) 2008-2009 Kohana Team
 * @license    http://kohanaphp.com/license
 */
class Database_Query_Builder_Select extends Kohana_Database_Query_Builder_Select
{

    /**
     * @var parts of allow modify method
     */
    private $_parts = array('select', 'from', 'join', 'where', 'group_by', 'having', 'order_by', 'limit', 'offset');

    /**
     * 获取 db select 组件
     *
     * @param  string  Part of select
     * @return mixed
     */
    public function get_part($part)
    {
        if ( ! in_array($part, $this->_parts))
        {
            throw new Database_Exception('Unknown database select part : ":part"',
                array(':part' => $part));
        }

        return $this->{"_$part"};
    }

    /**
     * 重置 db select 组件
     *
     * @param  string  Part of select
     * @param  mixed   Value of part
     * @return Database_Query_Builder_Select
     */
    public function reset_part($part, $value = NULL)
    {
        if ( ! in_array($part, $this->_parts))
        {
            throw new Database_Exception('Unknown database select part : ":part"',
                array(':part' => $part));
        }

        if ($part == 'limit' OR $part == 'offset')
        {
            ! is_numeric($value) AND $value = NULL;
        }
        elseif (empty($value))
        {
            $value = array();
        }

        $this->{"_$part"} = $value;

        return $this;
    }

    /**
     * 用于记录数统计
     *
     * @param   mixed  Database instance or name of instance
     * @return  int
     */
    public function __count_all($db = NULL)
    {
        if ( ! is_object($db))
        {
            // Get the database instance
            $db = Database::instance($db);
        }

        // Callback to quote identifiers
        $quote_ident = array($db, 'quote_identifier');

        // Rebuild select columns
        if ($this->_distinct === TRUE)
        {
            if (empty($this->_select) OR (count($this->_select) == 1 AND $this->_select[0] == '*'))
            {
                $part = ' *';
            }
            else
            {
                foreach ($this->_select as & $col)
                {
                    if ($col instanceof Database_Expression)
                    {
                        $col = $col->__toString();
                    }
                    else
                    {
                        $col = call_user_func($quote_ident, is_array($col) ? $col[0] : $col);
                    }
                }
                $part = implode(', ', array_unique($this->_select));
            }
            $this->_select = array(DB::expr('COUNT(DISTINCT ' . $part . ')'));
        }
        else
        {
            foreach($this->_group_by as & $col)
            {
                if ($col instanceof Database_Expression)
                {
                    $col = $col->__toString();
                }
                else
                {
                    $col = call_user_func($quote_ident, is_array($col) ? $col[0] : $col);
                }
            }
            $part = implode(', ', array_unique($this->_group_by));

            $this->_select = empty($part) ?
                array(DB::expr('COUNT(0)')) :
                array(DB::expr('COUNT(DISTINCT ' . $part . ')'));
        }

        // Rebuild distinct
        $this->_distinct = FALSE;

        // Disable [order, group, limit, offset]
        $this->_order_by = $this->_group_by = array();
        $this->_limit = $this->_offset = $this->_last_join = NULL;

        // $this->_having   = array();
        // $this->_parameters = array();

        $data = $this->execute($db)->as_array();

        return isset($data[0]) ? current($data[0]) : 0;
    }

    /**
     * 统计记录数
     *
     * @param   mixed  Database instance or name of instance
     * @return  int
     */
    public function count_all($db = NULL)
    {
        $new_obj = clone $this;

        return (int) $new_obj->__count_all($db);
    }

    /**
     * 以数组格式返回
     *
     * @param   mixed  Database instance or name of instance
     * @return  array
     */
    public function fetch_all($db = NULL)
    {
        $result = $this->execute($db);

        return ($this->_as_object) ? $result : $result->as_array();
    }

    /**
     * 获取第一条记录
     *
     * @param   mixed  Database instance or name of instance
     * @return  array
     */
    public function fetch_row($db = NULL)
    {
        $result = $this->limit(1)->execute($db);

        if (count($result))
        {
            foreach ($result as $row)
            {
                return $row;
            }
        }

        return NULL;
    }

    /**
     * 获取第一条第一列的记录
     *
     * @param   mixed  Database instance or name of instance
     * @return  mixed
     */
    public function fetch_one($db = NULL)
    {
        $data = $this->fetch_row($db);

        if (is_array($data) AND ! empty($data))
        {
            return current($data);
        }

        return NULL;
    }

    /**
     * 获取第一条某指定列的记录
     *
     * @param  string  Column name of result
     * @param   mixed  Database instance or name of instance
     * @return string
     */
    public function fetch_column($column, $db = NULL)
    {
        $data = $this->fetch_row($db);

        return isset($data[$column]) ? $data[$column] : NULL;
    }

}